package cn.com.duiba.millionaire.center.biz.service.impl;

import cn.com.duiba.consumer.center.api.dto.ConsumerDto;
import cn.com.duiba.consumer.center.api.remoteservice.RemoteConsumerService;
import cn.com.duiba.developer.center.api.domain.dto.AppSimpleDto;
import cn.com.duiba.developer.center.api.remoteservice.RemoteAppService;
import cn.com.duiba.millionaire.center.api.dto.MillionaireConsumerAccountRecordDto;
import cn.com.duiba.millionaire.center.api.dto.MillionaireConsumerDto;
import cn.com.duiba.millionaire.center.api.dto.MillionaireWithdrawDto;
import cn.com.duiba.millionaire.center.api.enums.AccountTypeEnum;
import cn.com.duiba.millionaire.center.api.enums.AppConfigProNameEnum;
import cn.com.duiba.millionaire.center.api.enums.WithdrawStatusEnum;
import cn.com.duiba.millionaire.center.biz.exception.BusinessException;
import cn.com.duiba.millionaire.center.biz.exception.ErrorCode;
import cn.com.duiba.millionaire.center.biz.mq.RocketMQTopicConstant;
import cn.com.duiba.millionaire.center.biz.service.*;
import cn.com.duiba.paycenter.client.RpcResult;
import cn.com.duiba.paycenter.client.WithdrawServiceClient;
import cn.com.duiba.paycenter.enums.PayAccountTypeEnum;
import cn.com.duiba.paycenter.enums.PayOrderBizTypeEnum;
import cn.com.duiba.paycenter.enums.PayOrderStatusEnum;
import cn.com.duiba.paycenter.enums.WithdrawBizTypeEnum;
import cn.com.duiba.paycenter.message.FundTransferCallbackMessage;
import cn.com.duiba.paycenter.message.FundTransferRequestMessage;
import cn.com.duiba.paycenter.params.FundTransferRequestParams;
import cn.com.duiba.paycenter.params.WithdrawParams;
import cn.com.duiba.paycenter.remoteservice.RemoteFundTransferService;
import cn.com.duiba.paycenter.result.FundTransferResult;
import cn.com.duiba.paycenter.result.WithdrawResult;
import org.apache.commons.lang.StringUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

import java.util.List;

/**
 * Created by xiaoxuda on 2018/2/1.
 */
@Service
public class WithdrawAlipayServiceImpl implements WithdrawAlipayService {
    private static final Logger LOGGER = LoggerFactory.getLogger(WithdrawAlipayServiceImpl.class);

    @Autowired
    private RocketMQTopicConstant rocketMQTopicConstant;
    @Autowired
    private RemoteConsumerService remoteConsumerService;
    @Autowired
    private RemoteFundTransferService remoteFundTransferService;
    @Autowired
    private MillionaireWithdrawService millionaireWithdrawService;
    @Autowired
    private MillionaireConsumerService millionaireConsumerService;
    @Autowired
    private ConsumerAccountRecordService consumerAccountRecordService;
    @Autowired
    private WithdrawServiceClient withdrawServiceClient;
    @Autowired
    private RemoteAppService remoteAppService;
    @Autowired
    private MillionaireAppConfigService millionaireAppConfigService;

    @Override
    public void applyAlipayTransfer(MillionaireWithdrawDto withdraw, AppSimpleDto app){
        ConsumerDto consumer = remoteConsumerService.find(withdraw.getConsumerId());
        if(StringUtils.isBlank(consumer.getLastAlipay()) || StringUtils.isBlank(consumer.getLastRealname())){
            throw new BusinessException("支付宝信息错误");
        }
        FundTransferRequestMessage message = new FundTransferRequestMessage();
        message.setTopic(rocketMQTopicConstant.getWithdrawTopic());
        message.setTag(rocketMQTopicConstant.getWithdrawTag());
        message.setKey(PayOrderBizTypeEnum.CONSUMER_WITHDRAW_MILLIONARIE.name());
        FundTransferRequestParams requestParams = new FundTransferRequestParams();
        requestParams.setPayeeType(PayAccountTypeEnum.ALIPAY);
        requestParams.setPayeeNo(consumer.getLastAlipay());
        requestParams.setPayeeName(consumer.getLastRealname());
        requestParams.setAmount(withdraw.getAmount().longValue());
        requestParams.setBizType(PayOrderBizTypeEnum.CONSUMER_WITHDRAW_MILLIONARIE);
        requestParams.setBizNo(withdraw.getId().toString());
        requestParams.setRemark(app.getName() + "-冲顶大会奖金");
        message.setRequestParams(requestParams);
        remoteFundTransferService.asynFundTransfer(message);
    }

    @Override
    public void withdrawAlipayCallback(FundTransferCallbackMessage result) {
        try {
            if (PayOrderStatusEnum.SUCCESS.equals(result.getResult().getTransferStatus())) {
                millionaireWithdrawService.update2Success(Long.valueOf(result.getRequestParams().getBizNo()));
            } else if (PayOrderStatusEnum.EXCEPTION.equals(result.getResult().getTransferStatus())) {
                return;//卡单
            } else if (PayOrderStatusEnum.FAIL.equals(result.getResult().getTransferStatus())) {
                MillionaireWithdrawDto withdraw = millionaireWithdrawService.findById(
                        Long.parseLong(result.getRequestParams().getBizNo()));
                if(!WithdrawStatusEnum.DEV_PAYED.equals(withdraw.getWithdrawStatus())){
                    throw new BusinessException("申请状态错误");
                }
                AppSimpleDto app = remoteAppService.getSimpleApp(withdraw.getAppId()).getResult();
                paybackDeveloperAccount(withdraw, app);
                paybackConsumerAccount(withdraw, result.getResult());
            }
        }catch (BusinessException e){
            LOGGER.info("提现支付响应处理失败, errMsg={}", e.getMessage(), e);
        }
    }

    //事务控制
    private void paybackConsumerAccount(MillionaireWithdrawDto withdraw, FundTransferResult result) {
        Exception processException = null;
        try {
            MillionaireConsumerDto millConsumer = millionaireConsumerService.select4Update(withdraw.getConsumerId());
            if (millConsumer == null) {
                throw new BusinessException("锁定账户失败");
            }
            MillionaireConsumerAccountRecordDto record = consumerAccountRecordService
                    .findByConsumerIdAndBizTypeAndBizId(withdraw.getConsumerId(),
                            AccountTypeEnum.WITHDRAW_FAIL_PAYBACK.getCode(), String.valueOf(withdraw.getId()));
            if (record != null) {
                throw new BusinessException(ErrorCode.RE_SUBMIT);
            }
            record = new MillionaireConsumerAccountRecordDto();
            record.setConsumerId(withdraw.getConsumerId());
            record.setAppId(withdraw.getAppId());
            record.setBizType(AccountTypeEnum.WITHDRAW_FAIL_PAYBACK.getCode());
            record.setBizId(String.valueOf(withdraw.getId()));
            record.setAmount(withdraw.getAmount());
            record = consumerAccountRecordService.insert(record);
            if (record.getId() == null) {
                throw new BusinessException("创建账户变更记录失败");
            }

            boolean deductRet = millionaireConsumerService.withdrawCashPayback(record.getConsumerId(), record.getAmount());
            if (!deductRet) {
                throw new BusinessException("用户余额返还失败");
            }
            String failMsg = result.getMessage();
            if(StringUtils.length(failMsg) > 255){
                failMsg = failMsg.substring(0, 255);
            }
            millionaireWithdrawService.update2Fail(withdraw.getId(), failMsg);
        } catch (Exception e) {
            processException = e;
            throw e;
        } finally {
            if (processException != null) {
                //TODO transaction.setRollbackOnly
            }
            //TODO transaction submit
        }
    }

    private void paybackDeveloperAccount(MillionaireWithdrawDto withdraw, AppSimpleDto app){
        Long appId = withdraw.getAppId();
        List<Long> appIds = millionaireAppConfigService.findAppIdByPropName(AppConfigProNameEnum.ALIPAY_DUIBA.getPropName());
        //不需要扣开发者资金,由兑吧自己支付,不做回滚操作
        if(appIds.contains(appId)){
            return;
        }
        WithdrawParams withdrawParams = new WithdrawParams();
        withdrawParams.setDeveloperId(app.getDeveloperId());
        withdrawParams.setAppId(withdraw.getAppId());
        withdrawParams.setConsumerId(withdraw.getConsumerId());
        withdrawParams.setBizType(WithdrawBizTypeEnum.USER_MILLIONAIRE);
        withdrawParams.setBizId(withdraw.getId());
        withdrawParams.setMoney(withdraw.getDevAmount().longValue());
        withdrawParams.setMemo("冲顶大会奖金退回");
        RpcResult<WithdrawResult> rpcResult = withdrawServiceClient.userWithdrawCashPaybackApply(withdrawParams);
        if(!rpcResult.isOpSuccess() || !Boolean.TRUE.equals(rpcResult.getResult().getSuccess())){
            throw new BusinessException("返还app余额失败");
        }
    }
}
